﻿using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace xLib
{
    public static class SettingsDumper
    {
        #region vars

        private static string SettingsPath
        {
            get
            {
                var AssName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
                return Application.StartupPath + "\\" + AssName + ".config.ini";
            }
        }
        #endregion

        #region public
        /// <summary>
        /// Add in form constructor after InitializeComponent();
        /// </summary>
        static public void Init(Form form,bool savePosition=true)
        {
            form.Closing += form_Closing;
            ProcessControls(form.Controls, LoadDelegate, form.GetType().Name);
            if (savePosition)
            {
                var pos = LoadPosition(form);
                if (pos != null)
                {
                    form.StartPosition = FormStartPosition.Manual;
                    form.Top = pos.Item1;
                    form.Left = pos.Item2;
                    form.Width = pos.Item3;
                    form.Height = pos.Item4;
                }
            }
        }

        public static void SaveAll(Form form)
        {
            ProcessControls(form.Controls, SaveDelegate, form.GetType().Name);
            SavePosition(form);
        }

        private static void SavePosition(Form form)
        {
            if (form.WindowState == FormWindowState.Minimized)
            {
                return;
            }

            if (form.Top < 0 || form.Left < 0)
            {
                return;
            }

            IniWriteValue(form.GetType().Name, "FormTop", form.Top.ToString());
            IniWriteValue(form.GetType().Name, "FormLeft", form.Left.ToString());
            IniWriteValue(form.GetType().Name, "FormWidth", form.Width.ToString());
            IniWriteValue(form.GetType().Name, "FormHeight", form.Height.ToString());
        }

        private static Tuple<int,int,int,int> LoadPosition(Form form)
        {
            try
            {
                return new Tuple<int, int,int,int>(int.Parse(IniReadValue(form.GetType().Name, "FormTop")),
                                           int.Parse(IniReadValue(form.GetType().Name, "FormLeft")),
                                           int.Parse(IniReadValue(form.GetType().Name, "FormWidth")),
                                           int.Parse(IniReadValue(form.GetType().Name, "FormHeight")));
            }catch{}
            return null;
        }

        #endregion

        #region private

        static void form_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SavePosition((Form)sender);
            ProcessControls(((Form)sender).Controls, SaveDelegate, sender.GetType().Name);
        }

        static private void ProcessControls(Control.ControlCollection controls, ProcessControlDelegate func, string section)
        {
            foreach (object obj in controls)
            {
                if (obj is TabControl)
                {
                    foreach (TabPage o in (((TabControl)obj).TabPages))
                    {
                        ProcessControls(o.Controls, func, section);
                    }
                }
                if (obj is GroupBox)
                    ProcessControls(((GroupBox)obj).Controls, func, section);
                if (
                    !(obj is TextBox) &&
                    !(obj is RadioButton) &&
                    !(obj is ComboBox) &&
                    !(obj is CheckBox) &&
                    !(obj is ListBox) &&
                    !(obj is NumericUpDown) &&
                    !(obj is TabControl)
                    )
                    continue;
                func(obj, section);
            }
        }

        static private void SaveDelegate(object obj, string section)
        {
            if (obj is TabControl)
            {
                IniWriteValue(section, ((TabControl)obj).Name, ((TabControl)obj).SelectedIndex.ToString());
            }
            if (obj is TextBox)
            {
                IniWriteValue(section, ((TextBox)obj).Name, AddQuotes(((TextBox)obj).Text));
            }
            if (obj is NumericUpDown)
            {
                IniWriteValue(section, ((NumericUpDown)obj).Name, ((NumericUpDown)obj).Value.ToString());
            }
            if (obj is ListBox)
            {
                IniWriteValue(section, ((ListBox)obj).Name, ((ListBox)obj).SelectedIndex.ToString());
            }

            if (obj is CheckBox)
            {
                IniWriteValue(section, ((CheckBox)obj).Name, ((CheckBox)obj).Checked.ToString());
            }
            if (obj is RadioButton)
            {
                IniWriteValue(section, ((RadioButton)obj).Name, ((RadioButton)obj).Checked.ToString());
            }
            if (obj is ComboBox)
            {
                IniWriteValue(section, ((ComboBox)obj).Name, ((ComboBox)obj).SelectedIndex.ToString());
            }
        }

        static private void LoadDelegate(object obj, string section)
        {
            if (obj is TextBox)
            {
                string value = IniReadValue(section, ((TextBox)obj).Name);
                if (value.Length > 0)
                    ((TextBox)obj).Text = value.Replace("{NEXTLINE}", "\r\n");
            }
            if (obj is ComboBox)
            {
                string value = IniReadValue(section, ((ComboBox)obj).Name);
                if (value.Length > 0 && int.Parse(value) < ((ComboBox)obj).Items.Count)
                    ((ComboBox)obj).SelectedIndex = int.Parse(value);
            }

            if (obj is NumericUpDown)
            {
                string value = IniReadValue(section, ((NumericUpDown)obj).Name);
                if (value.Length > 0)
                {
                    var num = ((NumericUpDown)obj);
                    var val = int.Parse(value);
                    if (num.Maximum < val)
                        num.Maximum = val;
                    num.Value = val;
                }
            }
            if (obj is ListBox)
            {
                string value = IniReadValue(section, ((ListBox)obj).Name);
                if (value.Length > 0)
                {
                    var val = Convert.ToInt32(value);
                    if (((ListBox)obj).Items.Count>val)
                    ((ListBox) obj).SelectedIndex = val;
                }
            }
            if (obj is CheckBox)
            {
                string value = IniReadValue(section, ((CheckBox)obj).Name);
                if (value.Length > 0)
                    ((CheckBox)obj).Checked = Convert.ToBoolean(value);
            }
            if (obj is RadioButton)
            {
                string value = IniReadValue(section, ((RadioButton)obj).Name);
                if (value.Length > 0)
                    ((RadioButton)obj).Checked = Convert.ToBoolean(value);
            }
            if (obj is TabControl)
            {
                string value = IniReadValue(section, ((TabControl)obj).Name);
                if (value.Length > 0)
                    ((TabControl)obj).SelectedIndex = Convert.ToInt32(value);
            }
        }

        static void IniWriteValue(string Section, string Key, string Value)
        {
            WritePrivateProfileString(Section, Key, Value, SettingsPath);
        }
        static string IniReadValue(string Section, string Key)
        {
            var temp = new StringBuilder(255);
            GetPrivateProfileString(Section, Key, "", temp, 255, SettingsPath);
            return temp.ToString();

        }

        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        static string AddQuotes(string str)
        {
            if (str.StartsWith(" ") || str.EndsWith(" "))
                return "\"" + str + "\"";
            return str.Replace("\r\n", "{NEXTLINE}");
        }

        private delegate void ProcessControlDelegate(object obj, string section);

        #endregion
    }
}
